#ifndef grf_TDC_H
#define grf_TDC_H

#include "grf.h"

namespace grf {

///////////////////////////////////////////////////////////////////////////////

struct TDC : public TDebug
{
  enum EBkMode
  {
    EBkMode_Opaque      = OPAQUE,
    EBkMode_Transparent = TRANSPARENT
  };
  enum ERegionMode
  {
    ERegionMode_And  = RGN_AND,
    ERegionMode_Copy = RGN_COPY,
    ERegionMode_Diff = RGN_DIFF,
    ERegionMode_Or   = RGN_OR,
    ERegionMode_Xor  = RGN_XOR
  };
  enum ETextAlign
  {
    ETextAlign_Left   = DT_LEFT,
    ETextAlign_Right  = DT_RIGHT,
    ETextAlign_Center = DT_CENTER
  };
  //
  HDC Handle;
  //
  TDC()       { Handle = NULL;/*scale=1.0;*/}
  TDC(HDC  H) { Handle = H;   /*scale=1.0;*/}
  TDC(TDC &DC){ Handle = DC.Handle; /*scale=DC.scale;*/}
  //
  operator HDC() { return Handle;}
  //
  void RoundRect(TRect Rect,TSize SizeEllipse)
  {
    //Rect.MMtoPT(scale); SizeEllipse.MMtoPT(scale);
    ::RoundRect (
      Handle,
      Rect.Left,Rect.Top,Rect.Right(),Rect.Bottom(),
      SizeEllipse.Width,SizeEllipse.Height
    );
  }
  //
  void FillRect (TRect Rect,const TBrush &Brush) { 
	  //Rect.MMtoPT(scale); 
	  ::RECT R = Rect; //R.right++; R.bottom++;
	  ::FillRect(Handle,&R,(TBrush&)Brush); 
  }
  void FrameRect(TRect Rect,const TBrush &Brush) { 
    //Rect.MMtoPT(scale); 
    ::RECT R = Rect; //R.right++; R.bottom++;
	  ::FrameRect(Handle,&R,(TBrush&)Brush); 
  }
  //
  void Rectangle(TRect R) { 
    //R.MMtoPT(scale); 
	  ::Rectangle(Handle,R.Left,R.Top,R.Right(),R.Bottom());
  }
  //
  void MoveTo(TPoint Pt) { /*Pt.MMtoPT(scale);*/ ::MoveToEx(Handle,Pt.X,Pt.Y,NULL);}
  void LineTo(TPoint Pt) { /*Pt.MMtoPT(scale);*/ ::LineTo(Handle,Pt.X,Pt.Y);}
  //
  void MoveTo(int X,int Y) { ::MoveToEx(Handle,/*MMtoPT*/(X),/*MMtoPT*/(Y),NULL);}
  void LineTo(int X,int Y) { ::LineTo(Handle,/*MMtoPT*/(X),/*MMtoPT*/(Y));}
  //
  void DrawHorzDotLine(int X,int Y,int W);
  void DrawVertDotLine(int X,int Y,int W);
  //
  void SetBkMode   (EBkMode V) { ::SetBkMode(Handle,V);}
  void SetTextColor(TColor  V) { ::SetTextColor(Handle,V);}
  //
  void Select(TFont   &V) { ::SetTextColor(Handle,V.Color); ::SelectObject(Handle,V); }
  void Select(TPen    &V) { ::SelectObject(Handle,V);}
  void Select(TBrush  &V) { ::SelectObject(Handle,V);}
  void Select(HBITMAP  V) { ::SelectObject(Handle,V);}

  //void Select(TBitmap &V) { ::SelectObject(Handle,V);}
  //void Select(TIcon   &V) { ::SelectObject(Handle,V);}
  //void Select(TImage  &V) { ::SelectObject(Handle,V.GetGdiObj());}
/*
  //
  TDC &operator = (TFont  &V) { Select(V); return *this;}
  TDC &operator = (TPen   &V) { Select(V); return *this;}
  TDC &operator = (TBrush &V) { Select(V); return *this;}
*/
  //
  void GetClipPT   (TRegion &V)                     { ::GetClipRgn(Handle,V);}
  void SelectClipPT(TRegion &V,ERegionMode RgnMode) { ::ExtSelectClipRgn(Handle,V,RgnMode);}
/******
  //
  void GetClip(TRegion &V) { ::GetClipRgn(Handle,V); V.PTtoMM(scale); }
  //
  void SelectClip(TRegion &V,ERegionMode RgnMode = ERegionMode_Copy)
  {
    V.MMtoPT(scale); ::ExtSelectClipRgn(Handle,V,RgnMode);
  }
*********/  
  //
  void SelectClip(TRect V,ERegionMode RgnMode = ERegionMode_Copy)
  {
	  //V.MMtoPT(scale); 
	  ::ExtSelectClipRgn(Handle,TRegion(V),RgnMode);
  }


  //
  //void SelectClipLP(TRegion &V,ERegionMode RgnMode = ERegionMode_Copy);
  //
  void SelectClipLP(TRect V,ERegionMode RgnMode = ERegionMode_Copy)
  {
	  //V.MMtoPT(scale); LPtoDP(V);
	  ::ExtSelectClipRgn(Handle,TRegion(V),RgnMode);
  }

/**********
  //
  void ExcludeClipRect(const TRect &V_)
  {
    TRect &V = (TRect&)V_; ::ExcludeClipRect
    (
      Handle,K(V.Left),K(V.Top),K(V.Right()),K(V.Bottom())
    );
  }
***********/  
  //
  void TextOut(TPoint Pt,char *Text)
  {
    //Pt.MMtoPT(scale); 
    ::TextOut(Handle,Pt.X,Pt.Y,Text,lstrlen(Text));
  }
  //
  void DrawText(TRect Rect,char *Text,ETextAlign TextAlign)
  {
    //Rect.MMtoPT(scale);
    RECT R(Rect); 
  	::DrawText(Handle,Text,lstrlen(Text),&R,TextAlign|DT_NOPREFIX);
  }
  //8888888888888888888888888888888888888888888888888
  void GetTextMetrics(::TEXTMETRIC &TM) { ::GetTextMetrics(Handle,&TM);}
  //
  TSize GetTextExtent(char *V,int Count)
  {
    SIZE Size; ::GetTextExtentPoint32(Handle,V,Count,&Size); 
    
	  if (Size.cy == 0){ 
		  ::TEXTMETRIC TM; ::GetTextMetrics(Handle,&TM); 
		  Size.cy = TM.tmHeight; 
	  }
    
    TSize Sz(Size.cx,Size.cy); //Sz.PTtoMM(scale); 
    return Sz;
  }
  TSize GetTextExtent(char *V) { return GetTextExtent(V,lstrlen(V));}
  //
  //8888888888888888888888888888888888888888888888888
  void BitBlt(TRect &RTo,TDC &DCFrom,TPoint &PtFrom)
  {
    ::BitBlt
    (
      Handle,        RTo.Left,RTo.Top,RTo.Width,RTo.Height,
      DCFrom.Handle, PtFrom.X,PtFrom.Y,
      SRCCOPY
    );
  }
  //
  bool Scroll(int InDx,int InDy,TRect InRScroll,TRect InRClip,TRect &OutRUpdate);

  // !!!!!!!!!
  void LPtoDP(TRect &R)
  {
    ::POINT P[2] = { R.Left, R.Top, R.Right(), R.Bottom() }; 
    ::LPtoDP(Handle,P,2);
    R.Left = P[0].x; R.Top = P[0].y; R.SetRight(P[1].x); R.SetBottom(P[1].y);
  }
  void LPtoDP(::RECT &R)
  {
    ::POINT P[2] = { R.left, R.top, R.right, R.bottom }; 
    ::LPtoDP(Handle,P,2);
    R.left = P[0].x; R.top = P[0].y; R.right = P[1].x; R.bottom = P[1].y;
  }
  void DPtoLP(::RECT &R)
  {
    ::POINT P[2] = { R.left, R.top, R.right, R.bottom }; 
    ::DPtoLP(Handle,P,2);
    R.left = P[0].x; R.top = P[0].y; R.right = P[1].x; R.bottom = P[1].y;
  }

  //
  //void SetScale(double Scale) {	scale = Scale;}
/********  
  int MMtoPT(int V) { return svl::MMtoPT(V,scale); }
  int PTtoMM(int V) { return svl::PTtoMM(V,scale); }

  int MMtoPT_Scroll(int V) { return svl::MMtoPT_Scroll(V,scale); }
  int PTtoMM_Scroll(int V) { return svl::PTtoMM_Scroll(V,scale); }
**********/  

/**********
  void K( RECT &_rect ){
	  int W = _rect.right  - _rect.left;
	  int H = _rect.bottom - _rect.top;

	  _rect.bottom = K(_rect.bottom);
	  _rect.left   = K(_rect.left);

	  _rect.right  = _rect.left + K(W);
	  _rect.bottom = _rect.top  + K(H);

	  //_rect.right  = K(_rect.right);
	  //_rect.top    = K(_rect.top);
  }
***************/  
/********
  void K( TRect &_rect ){
	  _rect.Left   = K(_rect.Left);
	  _rect.Top    = K(_rect.Top);

	  _rect.Width   = K(_rect.Width);
	  _rect.Height  = K(_rect.Height);

	  //_rect.SetRight(K(_rect.Right()));
	  //_rect.SetBottom(K(_rect.Bottom()));
  }
***********/

/**************
  void uK( RECT &_rect ){
	  int W = _rect.right  - _rect.left;
	  int H = _rect.bottom - _rect.top;

	  _rect.bottom = uK(_rect.bottom);
	  _rect.left   = uK(_rect.left);

	  _rect.right  = _rect.left + uK(W);
	  _rect.bottom = _rect.top  + uK(H);

	  //_rect.right  = uK(_rect.right);
	  //_rect.top    = uK(_rect.top);
  }
****************/
 
private:
  //double scale;
  svl_Except;
};

////////////////////////////////////////////////////////////////////////////////

struct TClientDC : public TDC
{
  svl::TWindow &Window;
  //
  operator HDC() { return TDC::Handle;}
  //
  TClientDC(svl::TWindow &Window_) : Window(Window_)
  {
    TDC::Handle = ::GetDC(Window);
    //TDC::SetScale(Window.GetScale());
  }
 ~TClientDC() { ::ReleaseDC(Window,TDC::Handle);}
};

////////////////////////////////////////////////////////////////////////////////

struct TPaintDC : public TDC
{
  svl::TWindow &Window;
  TRect RClientPaint;
  //
  TPaintDC(svl::TWindow &Window_) : Window(Window_)
  {
    TDC::Handle = ::BeginPaint(Window,&ps);
    //TDC::SetScale(Window.GetScale());
    RClientPaint = ps.rcPaint;
    //RClientPaint.PTtoMM(Window.GetScale());
  }
 ~TPaintDC() { ::EndPaint(Window,&ps);}
  //
  void operator = (const TPaintDC &V) { Except("operator = (const TPaintDC &V)");}

private:
  svl_Except;
  ::PAINTSTRUCT ps;
};

////////////////////////////////////////////////////////////////////////////////

struct TMemoryDC : public TDC
{
  TSize Size;
  //
  TMemoryDC(HDC DC,TSize Size)
  {
    this->Size = Size;
    TDC::Handle = ::CreateCompatibleDC(DC);
    hBitmap = ::CreateCompatibleBitmap(DC,Size.Width,Size.Height);
    ::SelectObject(TDC::Handle,hBitmap);
  }
 ~TMemoryDC()
  {
    ::DeleteDC(TDC::Handle);
    ::DeleteObject(hBitmap);
  }
  //
  operator HDC() { return TDC::Handle;}
  //
  void CopyTo(TRect RTo,TDC &DCTo,TPoint PtFrom)
  {
    ::BitBlt
    (
      DCTo,   RTo.Left,RTo.Top,RTo.Width,RTo.Height,
      Handle, PtFrom.X,PtFrom.Y,
      SRCCOPY
    );
  }

private:
  HBITMAP hBitmap;
};

////////////////////////////////////////////////////////////////////////////////
}

#endif
